imx: imx8qx: add domain suspend/resume support
authorAnson Huang <[email protected]>
Thu, 12 Jul 2018 06:17:19 +0000 (14:17 +0800)
committerAnson Huang <[email protected]>
Thu, 12 Jul 2018 08:15:32 +0000 (16:15 +0800)
Add domain suspend/resume support, Linux kernel
can "echo mem > /sys/power/state" to put system
into suspend mode, all CPUs and cluster will be
powered off and can be waked up if irq pending
in GIC, tested on i.MX8QX MEK board.

Signed-off-by: Anson Huang <[email protected]>
plat/imx/common/imx8_psci.c
plat/imx/common/include/plat_imx8.h
plat/imx/imx8qx/imx8qx_psci.c
plat/imx/imx8qx/platform.mk

index 37eda3e6ac5e197198a0915ab7e858328fa175bc..22a531bf8313b449d279eddbc7914c23542e9483 100644 (file)
@@ -27,3 +27,20 @@ void __dead2 imx_system_reset(void)
        panic();
 }
 
+int imx_validate_power_state(unsigned int power_state,
+                        psci_power_state_t *req_state)
+{
+       /* TODO */
+       return PSCI_E_INVALID_PARAMS;
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+       unsigned int i;
+
+       /* CPU & cluster off, system in retention */
+       for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+               req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+       req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
+}
+
index 3b5f4ec6b2de1495fb9f64172fbdf54d76fd245a..a333bfbe11202a1f4a752ed12a1bdf3661e1c526 100644 (file)
@@ -8,6 +8,7 @@
 #define __PLAT_IMX8_H__
 
 #include <gicv3.h>
+#include <psci.h>
 
 unsigned int plat_calc_core_pos(uint64_t mpidr);
 void imx_mailbox_init(uintptr_t base_addr);
@@ -19,4 +20,7 @@ void plat_gic_pcpu_init(void);
 
 void __dead2 imx_system_off(void);
 void __dead2 imx_system_reset(void);
+int imx_validate_power_state(unsigned int power_state,
+                       psci_power_state_t *req_state);
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state);
 #endif /*__PLAT_IMX8_H__ */
index 7a6e822b743baba7be4166e3b8103f08ce881be9..f1df267a814c912df1537681d1a054e52dff5c73 100644 (file)
@@ -18,13 +18,6 @@ const static int ap_core_index[PLATFORM_CORE_COUNT] = {
        SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3
 };
 
-plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
-                                            const plat_local_state_t *target_state,
-                                            unsigned int ncpu)
-{
-       return 0;
-}
-
 int imx_pwr_domain_on(u_register_t mpidr)
 {
        int ret = PSCI_E_SUCCESS;
@@ -71,6 +64,29 @@ void imx_pwr_domain_off(const psci_power_state_t *target_state)
        tf_printf("turn off core:%d\n", cpu_id);
 }
 
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+       u_register_t mpidr = read_mpidr_el1();
+       unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       plat_gic_cpuif_disable();
+
+       sc_pm_set_cpu_resume_addr(ipc_handle, ap_core_index[cpu_id], BL31_BASE);
+       sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+               SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+       u_register_t mpidr = read_mpidr_el1();
+       unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+               SC_PM_PW_MODE_ON);
+
+       plat_gic_cpuif_enable();
+}
+
 static const plat_psci_ops_t imx_plat_psci_ops = {
        .pwr_domain_on = imx_pwr_domain_on,
        .pwr_domain_on_finish = imx_pwr_domain_on_finish,
@@ -78,6 +94,10 @@ static const plat_psci_ops_t imx_plat_psci_ops = {
        .system_off = imx_system_off,
        .system_reset = imx_system_reset,
        .pwr_domain_off = imx_pwr_domain_off,
+       .pwr_domain_suspend = imx_domain_suspend,
+       .pwr_domain_suspend_finish = imx_domain_suspend_finish,
+       .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+       .validate_power_state = imx_validate_power_state,
 };
 
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
@@ -86,5 +106,17 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
        imx_mailbox_init(sec_entrypoint);
        *psci_ops = &imx_plat_psci_ops;
 
+       /* Request low power mode for A35 cluster, only need to do once */
+       sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
+
+       /* Request RUN and LP modes for DDR, system interconnect etc. */
+       sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
+               SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
+       sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
+               SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
+       sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
+               SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
+               SC_PM_PW_MODE_STBY);
+
        return 0;
 }
index 7d6e3fdfe1a1a5500b912e66e6012bc3bf2e97e4..067661890bee70b5a30db9c21cf9aad1b4a6e093 100644 (file)
@@ -21,6 +21,7 @@ BL31_SOURCES          +=      plat/imx/common/lpuart_console.S        \
                                plat/imx/imx8qx/imx8qx_psci.c           \
                                plat/imx/common/imx8_topology.c         \
                                plat/imx/common/imx8_psci.c             \
+                               plat/common/plat_psci_common.c          \
                                lib/xlat_tables/xlat_tables_common.c    \
                                lib/xlat_tables/aarch64/xlat_tables.c   \
                                lib/cpus/aarch64/cortex_a35.S           \